﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using HWR_Ants.Classes;

namespace HWR_Ants.Forms
{
    public partial class fHWR_Ants : Form
    {
        #region needed Vars
        private TSP_File tspFile;
        private Bitmap _Bitmap;
        private Image drawImage;
        private Size size;
        private delegate void MapUpdateDelegate(Map sender, UpdateEventArgs e);
        BackgroundWorker bw = new BackgroundWorker();
        Map mapFindTour;
        private const int RADIUS = 3;
        UpdateEventArgs uea_last = null;
        Map map_last = null;
        private int divident = 1;
        DateTime _startTime;
        DateTime _endTime;
        double globalBestValue = 0;
        double gesamtlänge = 0;
        double durchschnittslaenge_Global = 0;
        #endregion

        #region FormUpdateEvents
        /// <summary>
        /// default Constructor
        /// </summary>
        public fHWR_Ants()
        {
            InitializeComponent();
            openFileDialog1.InitialDirectory = Application.StartupPath;
            // this.WindowState = FormWindowState.Maximized;
            openFileDialog1.RestoreDirectory = true;
            Tools.Tools.ActiveCurrentOptions = Tools.Tools.getCurrentStoredOptions();
            ctms_Item_StartStop.Enabled = false;
            tsmi_Schliessen.Enabled = false;
            reloadStandardPicture();   
        }

        public fHWR_Ants(TSP_File tspfile)
        {
            InitializeComponent();
            openFileDialog1.InitialDirectory = Application.StartupPath;
            // this.WindowState = FormWindowState.Maximized;
            openFileDialog1.RestoreDirectory = true;
            Tools.Tools.ActiveCurrentOptions = Tools.Tools.getCurrentStoredOptions();
            ctms_Item_StartStop.Enabled = false;
            tsmi_Schliessen.Enabled = false;
            tspFile = tspfile;
            ctms_Item_StartStop.Enabled = true;
            tsmi_Schliessen.Enabled = true;
            Invalidate();
            // reloadStandardPicture();
        }

        /// <summary>
        /// updates the map and draws the picture
        /// </summary>
        /// <param name="sender">Map to draw</param>
        /// <param name="e">UpdateEventargs with best solution currently</param>
        void map_UpdateEvent(Map sender, UpdateEventArgs e)
        {
            uea_last = e;
            map_last = sender;
            if (InvokeRequired)
            {
                Invoke(new MapUpdateDelegate(map_UpdateEvent), new object[] { sender, e });
            }
            else
            {
                System.Threading.Thread.Sleep(200);
                // System.Threading.Thread.Sleep(500);
                if (sender != null)
                    drawImage = new Bitmap(Convert.ToInt32((tspFile.Highest_X_Coord / divident) + 10), Convert.ToInt32((tspFile.Highest_Y_Coord / divident) + 10));

                using (Graphics g = Graphics.FromImage(drawImage))
                {
                    if (sender == null)
                    {
                        sender = new Map(new MapWrapper(tspFile.Coordinates));

                        using (Pen p = new Pen(Color.FromArgb(26, Color.Blue), 2))
                        {
                            for (int i = 0; i < sender.Cities.Count - 1; i++)
                            {
                                for (int j = i + 1; j < sender.Cities.Count; j++)
                                {
                                    IList<City> il = sender.Cities;

                                    Road road = il.ElementAt(i).Roads(il.ElementAt(j));

                                    Point p1 = il.ElementAt(i).Coord;
                                    p1.X = Convert.ToInt32(p1.X / divident);
                                    p1.Y = Convert.ToInt32(p1.Y / divident);
                                    Point p2 = il.ElementAt(j).Coord;
                                    p2.X = Convert.ToInt32(p2.X / divident);
                                    p2.Y = Convert.ToInt32(p2.Y / divident);
                                    g.DrawLine(p, p1, p2);
                                }
                            }
                        }

                        Pen pen = new Pen(Color.Black, RADIUS / 3);
                        foreach (Point p in tspFile.Coordinates.Values)
                        {
                            g.DrawEllipse(pen, p.X - RADIUS, p.Y - RADIUS, RADIUS * 2, RADIUS * 2);
                            // g.DrawEllipse(Pens.Black, Convert.ToInt32(p.X / divident), Convert.ToInt32(p.Y / divident), 5, 5);
                        }

                    }
                    else
                    {
                        fillTextBoxes(sender,e);
                        double sum_pheromones = 0;
                        int counter = 0;

                        foreach (Road r in sender.Roads.ToArray())
                        {
                            sum_pheromones += r.PheromonValue;
                            counter++;
                        }
                        double factor = 255 * counter;
                        // double factor = 255 ;

                        for (int i = 0; i < sender.Cities.Count - 1; i++)
                        {
                            for (int j = i + 1; j < sender.Cities.Count; j++)
                            {
                                IList<City> il = sender.Cities;

                                Road road = il.ElementAt(i).Roads(il.ElementAt(j));
                                int alpha = Math.Min(Math.Max(Convert.ToInt32(road.PheromonValue / sum_pheromones * factor), 0), 255);
                                Point p1 = il.ElementAt(i).Coord;
                                Point p2 = il.ElementAt(j).Coord;
                                p1.X = Convert.ToInt32(p1.X / divident);
                                p1.Y = Convert.ToInt32(p1.Y / divident);
                                p2.X = Convert.ToInt32(p2.X / divident);
                                p2.Y = Convert.ToInt32(p2.Y / divident);

                                using (Pen p = new Pen(Color.FromArgb(alpha, Color.Blue), 2))
                                {
                                    g.DrawLine(p, p1, p2);
                                }
                            }
                        }

                        for (int j = 0; j < sender.Cities.Count - 1; j++)
                        {
                            IEnumerable<City> il = e.BestTour;

                            Road road = il.ElementAt(j).Roads(il.ElementAt(j + 1));
                            Point p1 = il.ElementAt(j).Coord;
                            Point p2 = il.ElementAt(j + 1).Coord;
                            p1.X = Convert.ToInt32(p1.X / divident);
                            p1.Y = Convert.ToInt32(p1.Y / divident);
                            p2.X = Convert.ToInt32(p2.X / divident);
                            p2.Y = Convert.ToInt32(p2.Y / divident);

                            using (Pen p = new Pen(Color.Red, 4))
                            {
                                g.DrawLine(p, p1, p2);
                            }

                            if (j == sender.Cities.Count - 2)
                            {
                                road = il.ElementAt(j + 1).Roads(il.ElementAt(0));
                                p1 = il.ElementAt(j + 1).Coord;
                                p2 = il.ElementAt(0).Coord;
                                p1.X = Convert.ToInt32(p1.X / divident);
                                p1.Y = Convert.ToInt32(p1.Y / divident);
                                p2.X = Convert.ToInt32(p2.X / divident);
                                p2.Y = Convert.ToInt32(p2.Y / divident);
                                using (Pen p = new Pen(Color.Red, 4))
                                {
                                    g.DrawLine(p, p1, p2);
                                }

                            }
                        }
                        Pen pen = new Pen(Color.Black, RADIUS / 3);
                        foreach (Point p in tspFile.Coordinates.Values)
                        {
                            g.DrawEllipse(pen, p.X - RADIUS, p.Y - RADIUS, RADIUS * 2, RADIUS * 2);
                            // g.DrawEllipse(Pens.Black, Convert.ToInt32(p.X / divident), Convert.ToInt32(p.Y / divident), 5, 5);
                        }


                    }
                    drawImage = Tools.Tools.resizeImage(drawImage, size);
                    if (!tspFile.SelfCreated)
                        RotateFlip(RotateFlipType.Rotate180FlipX);
                    pb_DrawCity.Image = drawImage;
                }
            }
            // MessageBox.Show(e.ToString());
        }

        private void fillTextBoxes(Map sender, UpdateEventArgs e)
        {
            if (e == null)
            {
                fillTextBoxes(String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty);
            }
            else
            {
            if (globalBestValue > e.CurrentBestValue || globalBestValue == 0)
                globalBestValue = e.CurrentBestValue;

            gesamtlänge += e.LastValue;
            durchschnittslaenge_Global = gesamtlänge / e.CurrentIteration;

            e.TimeUsed = DateTime.Now.Subtract(_startTime);

            fillTextBoxes(
                e.CurrentIteration.ToString(),
                globalBestValue.ToString(),
                e.CurrentIterationBestValue.ToString(),
                e.TimeUsed.ToString(),
                e.LastValue.ToString(),
                durchschnittslaenge_Global.ToString()
                );
            }
        }

        private void fillTextBoxes(
            string iteration,
            string bestValue,
            string currentIterationBestValue,
            string time,
            string ds_Iteration,
            string ds_Global
            )
        {
            lb_AktuelleIterationOut.Text = iteration;
            lb_BesteLaengeOut.Text = bestValue;
            lb_BesteLaengeIterationOut.Text = currentIterationBestValue;
            lb_TimeOut.Text = time;
            lb_DSIOut.Text = ds_Iteration;
            lb_DSGOut.Text = ds_Global;
        }
        #endregion

        #region Formevents

        private void fHWR_Ants_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (bw != null && bw.IsBusy)
                ctms_Item_StartStop_Click(null, null);
        }

        private void fHWR_Ants_SizeChanged(object sender, EventArgs e)
        {
            if (tspFile == null)
            {
                reloadStandardPicture();
            }
            else
            {
                if (pb_DrawCity.Width == 0 && pb_DrawCity.Height == 0)
                    size = new Size(1, 1);
                else
                    size = new Size(pb_DrawCity.Width, pb_DrawCity.Height);
                Invalidate();
            }
            
        }
      
        private void fHWR_Ants_Paint(object sender, PaintEventArgs e)
        {
            if (tspFile == null)
            {
                return;
            }

            size = new Size(pb_DrawCity.Width, pb_DrawCity.Height);
            if (tspFile.Highest_X_Coord > 10000 || tspFile.Highest_Y_Coord > 10000)
                divident = 10;
            else
                divident = 1;

            drawImage = new Bitmap(Convert.ToInt32((tspFile.Highest_X_Coord / divident) + 20), Convert.ToInt32((tspFile.Highest_Y_Coord / divident) + 20));
            if (map_last != null && uea_last != null)
                map_UpdateEvent(map_last, uea_last);
            else
            {
                map_UpdateEvent(null, null);
                lb_AktuelleIterationOut.Text = "";
                lb_BesteLaengeOut.Text = "";
                lb_BesteLaengeIterationOut.Text = "";
                lb_TimeOut.Text = "";
                lb_DSIOut.Text = "";
                lb_DSGOut.Text = "";
            }

        }
        
        #endregion

        #region Backgroundworker Events

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            globalBestValue = 0;
            mapFindTour = new Map(new MapWrapper(tspFile.Coordinates));
            mapFindTour.UpdateEvent += new Map.UpdateEventHandler(map_UpdateEvent);
            _startTime = DateTime.Now;
            IEnumerable<City> temp = mapFindTour.FindTour();
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _endTime = DateTime.Now;
            // set via e.TimeUsed in fillTextboxes
            // uea_last.TimeUsed = _endTime.Subtract(_startTime);
            uea_last.DS_Global = durchschnittslaenge_Global;
            uea_last.Filename = tspFile.Filename_wo_extension;
            fAusgabe ausgabe = new fAusgabe(uea_last);
            ausgabe.Show();
            bw.DoWork -= new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            ctms_Item_StartStop.Text = "Start";
            durchschnittslaenge_Global = 0;
            gesamtlänge = 0;
        }

        #endregion

        #region needed Functions

        private void reloadStandardPicture()
        {
            Bitmap bmp = (Bitmap)Properties.Resources.ResourceManager.GetObject("TSP_ANT_LOGO");
            if (bmp != null)
            {
                // Bitmap bmp = new Bitmap(System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream("HWR_Ants.Properties.Resources.resources.TSP_ANT_LOGO.png"));
                Image img = Tools.Tools.resizeImage(bmp, new Size(pb_DrawCity.Width, pb_DrawCity.Height));
                pb_DrawCity.SizeMode = PictureBoxSizeMode.CenterImage;
                pb_DrawCity.Image = img;
            }
            Invalidate();
        }

        private void RotateFlip(RotateFlipType rotateFlipType)
        {
            Bitmap temp = (Bitmap)drawImage;
            Bitmap bmap = (Bitmap)temp.Clone();
            bmap.RotateFlip(rotateFlipType);
            drawImage = (Bitmap)bmap.Clone();
        }
        
        #endregion

        #region Toolstrip and Contextmenu Clicks

        private void tsmi_Einstellungen_Click(object sender, EventArgs e)
        {
            fOptions fo = new fOptions();
            fo.Show();
        }

        /*
        private void tsmi_Ausgabe_Click(object sender, EventArgs e)
        {
            fAusgabe fa = new fAusgabe();
            fa.Show();
        }
        */

        private void tsmi_Hilfe_Click(object sender, EventArgs e)
        {
            fAbout fa = new fAbout();
            fa.Show();
        }

        private void tsmi_Schliessen_Click(object sender, EventArgs e)
        {
            ctms_Item_StartStop.Enabled = false;
            tsmi_Schliessen.Enabled = false;
            tspFile = null;
            uea_last = null;
            map_last = null;
            gesamtlänge = 0;
            durchschnittslaenge_Global = 0;
            reloadStandardPicture();
            fillTextBoxes(null, null);
        }

        private void ctms_Item_StartStop_Click(object sender, EventArgs e)
        {
            if (bw.IsBusy)
            {
                bw.CancelAsync();
                if (mapFindTour != null)
                    mapFindTour.Stop();

                while (bw.IsBusy)
                {
                    Application.DoEvents();
                }
                bw.DoWork -= new DoWorkEventHandler(bw_DoWork);
                bw.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                ctms_Item_StartStop.Text = "Start";
            }
            else
            {
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                bw.WorkerReportsProgress = true;
                bw.WorkerSupportsCancellation = true;
                bw.RunWorkerAsync();
                ctms_Item_StartStop.Text = "Stop";
            }
        }
 
        private void tsmi_Oeffnen_Click(object sender, EventArgs e)
        {

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                if (openFileDialog1.FileName.Contains("\\"))
                    openFileDialog1.InitialDirectory = openFileDialog1.FileName.Substring(0, openFileDialog1.FileName.LastIndexOf("\\"));

                if (File.Exists(openFileDialog1.FileName))
                {
                    try
                    {
                        tspFile = new TSP_File(openFileDialog1.FileName);
                        _Bitmap = new Bitmap(pb_DrawCity.Width + 100, pb_DrawCity.Height + 20);
                        size = new Size(pb_DrawCity.Width, pb_DrawCity.Height);
                        ctms_Item_StartStop.Enabled = true;
                        tsmi_Schliessen.Enabled = true;
                        uea_last = null;
                        map_last = null;
                        gesamtlänge = 0;
                        durchschnittslaenge_Global = 0;
                        Invalidate();
                    }
                    catch (Exception ex)
                    {
                        tspFile = null;
                        MessageBox.Show(ex.Message);
                    }
                }
            }
        }

        #endregion

        private void neuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            fDrawForm draw = new fDrawForm();
            if (draw.ShowDialog() == DialogResult.OK)
            {

            }

            if (Tools.Tools.SAVEDTSPFILE != String.Empty)
            {
                tspFile = new TSP_File(Tools.Tools.SAVEDTSPFILE);
                Tools.Tools.SAVEDTSPFILE = String.Empty;
                _Bitmap = new Bitmap(pb_DrawCity.Width + 100, pb_DrawCity.Height + 20);
                size = new Size(pb_DrawCity.Width, pb_DrawCity.Height);
                ctms_Item_StartStop.Enabled = true;
                tsmi_Schliessen.Enabled = true;
                uea_last = null;
                map_last = null;
                gesamtlänge = 0;
                durchschnittslaenge_Global = 0;
                Invalidate();
            }
        }
    }
}
